package com.fplugin.uverify;

import android.Manifest;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;

import com.alibaba.fastjson.JSONObject;
import com.umeng.analytics.MobclickAgent;
import com.umeng.commonsdk.UMConfigure;
import com.umeng.umverify.UMVerifyHelper;
import com.umeng.umverify.listener.UMCustomInterface;
import com.umeng.umverify.listener.UMTokenResultListener;
import com.umeng.umverify.listener.UMPreLoginResultListener;
import com.umeng.umverify.listener.UMAuthUIControlClickListener;
import com.umeng.umverify.view.UMAbstractPnsViewDelegate;
import com.umeng.umverify.view.UMAuthRegisterViewConfig;
import com.umeng.umverify.view.UMAuthRegisterXmlConfig;
import com.umeng.umverify.view.UMAuthUIConfig;

import java.util.List;
import java.util.Map;

import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry;

/** UverifyPlugin */
public class UverifyPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
  private String TAG = "UverifyPlugin=>TAG";
  private UverifyUtil util;
  private UverifyUI ui;

  private MethodChannel methodChannel;

  private static Activity activity;
  private static Context context;

  private String appKey = "";
  private String appSecret = "";
  private String channel = "Umeng";
  private int timeout = 3000;
  private boolean loggerEnable;


  private UMVerifyHelper umVerifyHelper;
  private UMTokenResultListener mTokenListener;

  private int authPageOrientation = 0;

  private int mOldScreenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
  private Button vaildBtnPor, loginBtnPor, loginDialogBtnPor;
  private Button vaildBtnLand, loginBtnLand, loginDialogBtnLand;
  private TextView textView;
  private ProgressDialog progressDialog;

  @RequiresApi(api = Build.VERSION_CODES.P)
  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    try {
      switch (call.method) {
        case "init":
          init(call, result);
          break;
        case "preLogin":
          preLogin(call, result);
          break;
        case "getLoginToken":
          getLoginToken(call, result);
          break;
        case "quitLoginPage":
          quitLoginPage(call, result);
          break;
        case "hideLoginLoading":
            hideLoginLoading(call, result);
          break;
        case "getVerifyId":
          getVerifyId(call, result);
          break;
        case "getCurrentCarrierName":
          getCurrentCarrierName(call, result);
          break;
        case "addAuthRegistViewConfig":
          addAuthRegistViewConfig(call, result);
          break;
        case "addAuthRegisterXmlConfig":
          addAuthRegisterXmlConfig(call, result);
          break;
        default:
          result.notImplemented();
          break;
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  private void init(@NonNull MethodCall call, @NonNull final Result result) throws Exception {
    appKey = call.argument("appKey");
    appSecret = call.argument("appSecret");
    loggerEnable = call.argument("loggerEnable");
    timeout = call.argument("timeout");
    if( appSecret.equals("")) {
      throw new Exception("appSecret为空！");
    }
    UMConfigure.init(context, appKey, channel, UMConfigure.DEVICE_TYPE_PHONE, null);
    Log.d(TAG,"初始化成功");
    // 1.初始化获取token实例
    mTokenListener = new UMTokenResultListener() {
      @Override
      public void onTokenSuccess(String res) {
        Log.d(TAG, "onTokenSuccess:\n" + res);
        JSONObject jsonObject = JSONObject.parseObject(res);
        util.runMainThread(jsonObject, null, "sdkTokenEventListener");
      }

      @Override
      public void onTokenFailed(String res) {
        Log.d(TAG, "onTokenFailed:\n" + res);
        JSONObject jsonObject = JSONObject.parseObject(res);
        util.runMainThread(jsonObject, null, "sdkTokenEventListener");
      }
    };
    // 2.初始化SDK实例
    umVerifyHelper = UMVerifyHelper.getInstance(context, mTokenListener);
    // 3.设置SDK秘钥
    umVerifyHelper.setAuthSDKInfo(appSecret);
    // 4.设置token监听
    umVerifyHelper.setAuthListener(mTokenListener);

    // 5.检测终端网络环境是否支持一键登录或者号码认证
    if(!checkVerifyEnable(0)) {
      Log.d(TAG, "当前网络不支持，请检测蜂窝网络后重试");
      return;
    }
    // 设置SDK 是否开启日志
    umVerifyHelper.setLoggerEnable(loggerEnable);

    // 验证页面方向
    authPageOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
    if (Build.VERSION.SDK_INT == 26) {
      authPageOrientation = ActivityInfo.CONFIG_ORIENTATION;
    }
    setUIClickListener(call, null);
  }

  private void preLogin(@NonNull MethodCall call, @NonNull final Result result) {
    /**
     * 预取号码信息，建议在 APP 登录页初始化时调用，会提高后续授权页的打开速度，不会影响拉起授权页的成功率。
     * 不要在 App 启动初始化时调用，预取号接口有有效期，避免接口调用资源浪费
     * @param overdueTime 超时时间 单位ms
     * @param listener 预取结果回调函数
     */
    int _timeout = timeout;
    if (call.hasArgument("timeOut")) {
      _timeout = call.argument("timeOut");
    }
    // 6.若步骤4支持，则根据业务情况，调用预取号或者一键登录接口
    Log.d(TAG,"正在调用预取号接口，请等待回调结果后进行其他操作");
    umVerifyHelper.accelerateLoginPage(_timeout, new UMPreLoginResultListener() {
      @Override
      public void onTokenSuccess(final String vendor) {
        activity.runOnUiThread(new Runnable() {
          @Override
          public void run() {
            String message = "预取号成功！";
            JSONObject jsonObject = util.retJSONObject(600001, message, vendor);
            Log.d(TAG, vendor + message);
            util.runMainThread(jsonObject, result, null);
          }
        });
      }
      @Override
      public void onTokenFailed(final String vendor, final String res) {
        activity.runOnUiThread(new Runnable() {
          @Override
          public void run() {
            Log.d(TAG, vendor + "预取号失败:\n" + res);
            JSONObject jsonObject = JSONObject.parseObject(res);
            util.runMainThread(jsonObject, result, null);
          }
        });
      }
    });

  }

  private void getLoginToken(@NonNull MethodCall call, @NonNull final Result result) {
    setAuthUIConfig(call, result);
    umVerifyHelper.getLoginToken(context, timeout);
  }

  private void getVerifyId(@NonNull MethodCall call, @NonNull final Result result) {
    String id =  umVerifyHelper.getVerifyId(context);
    Log.d(TAG, "当前设备号:" + id);
    util.runMainThread(id, result, null);
  }

  private void getCurrentCarrierName(@NonNull MethodCall call, @NonNull final Result result) {
    String carrier =  umVerifyHelper.getCurrentCarrierName();
    Log.d(TAG, "当前运营商:" + carrier);
    util.runMainThread(carrier, result, null);
  }

  private void quitLoginPage(@NonNull MethodCall call, @NonNull final Result result) {
    umVerifyHelper.quitLoginPage();
    Log.d(TAG, "退出成功！");
  }

  private void hideLoginLoading(@NonNull MethodCall call, @NonNull final Result result) {
    umVerifyHelper.hideLoginLoading();
    Log.d(TAG, "关闭LoginLoading！");
  }

  // 一键登录页面添加由XML的自定义控件为完成，请期待
  private void addAuthRegisterXmlConfig(@NonNull MethodCall call, @NonNull final Result result) {
    Object xmlconfig = call.argument("xmlconfig");
    Log.d(TAG, "xml配置" + xmlconfig);
    if(xmlconfig != null ) {
      Map _xmlconfig = (Map) xmlconfig;
      Object layoutResId = util.getValueByMapKey(_xmlconfig, "layoutResId");
      if ( layoutResId != null) {
        int res_id = util.getResourceByReflect((String) layoutResId);
        Log.d(TAG, "xml====>>配置" + res_id);
        if(res_id > 0) {
          umVerifyHelper.addAuthRegisterXmlConfig(new UMAuthRegisterXmlConfig.Builder()
            .setLayout((int) res_id, new UMAbstractPnsViewDelegate() {
              @Override
              public void onViewCreated(View view) {
                findViewById(R.id.authsdk_login_view).setOnClickListener(new View.OnClickListener(){
                  @Override
                  public void onClick(View v) {
                    Log.d(TAG,"================>>"+ v);
                  }
                });
              }
            }).build());
        }
      }
    } else {
      return;
    }

    Map uiconfig = util.getValueByMethodCallArgument(call, "uiconfig");
    // UMeng builder
    UMAuthUIConfig.Builder builder = new UMAuthUIConfig.Builder();
    // 设置AuthUI，SDK授权界面原有UI
    setAuthUI(uiconfig, builder);
    umVerifyHelper.getLoginToken(context, timeout);
  }

  /**
   * @function 自定义授权界面 UI 、添加自定义控件
   * @param call
   * @param result
   */
  @RequiresApi(api = Build.VERSION_CODES.P)
  private void addAuthRegistViewConfig(@NonNull MethodCall call, @NonNull final Result result) {
    Log.d(TAG, "addAuthRegistViewConfig");

    // UMeng builder
    UMAuthUIConfig.Builder builder = new UMAuthUIConfig.Builder();
    Map uiconfig = util.getValueByMethodCallArgument(call, "uiconfig");

    // 设置AuthUI，SDK授权界面原有UI
    setAuthUI(uiconfig, builder);

    List<Map> widgetList = call.argument("widgets");
    if (widgetList != null) {
      createView(call, result, widgetList, builder);
    }

    umVerifyHelper.getLoginToken(context, timeout);
  }

  @RequiresApi(api = Build.VERSION_CODES.P)
  private  void createView(@NonNull MethodCall call, @NonNull final Result result, List<Map> widgetList, UMAuthUIConfig.Builder builder) {
    for (Map widgetMParams : widgetList) {
      // 新增自定义的控件
      String type = (String) widgetMParams.get("type");
      if (type.equals("textView")) {
        _addCustomTextViewWidget(widgetMParams, builder);
      } else if (type.equals("button")) {
        Log.e(TAG, "widgetList" + widgetList);
        _addCustomButtonWidget(widgetMParams, builder);
      } else {
        Log.e(TAG, "不支持的widget");
      }
      Object widgets = widgetMParams.get("widgets");
      if(widgets != null) {
        List<Map> _widgetList = (List<Map>) widgets;
        createView(call, result, _widgetList, new UMAuthUIConfig.Builder());
      }
    }
  }

  /**
   * @funtion setAuthUIConfig 自定义 SDK 原有的授权界面里的 UI
   * @param call
   * @param result
   */
  private void setAuthUIConfig(@NonNull MethodCall call, @NonNull Result result) {
    Log.d(TAG, "setAuthUIConfig");

    Map uiconfig = util.getValueByMethodCallArgument(call, "uiconfig");
    // UMeng builder
    UMAuthUIConfig.Builder builder = new UMAuthUIConfig.Builder();

    // 设置AuthUI，SDK授权界面原有UI
    setAuthUI(uiconfig, builder);

  }

  private void setAuthUI(Map uiconfig, UMAuthUIConfig.Builder builder) {
    umVerifyHelper.removeAuthRegisterXmlConfig();
    umVerifyHelper.removeAuthRegisterViewConfig();

    /// 授权页导航栏
    ui.setAuthUIBar(uiconfig, builder);

    /// 授权页Logo
    ui.setAuthUILogan(uiconfig, builder);

    /// 授权页Slogan
    ui.setAuthUISlogan(uiconfig, builder);

    /// 授权页号码栏
    ui.setAuthUIPhone(uiconfig, builder);

    // 授权页登录按钮
    ui.setAuthUILoginButton(uiconfig, builder);

    /// 授权页隐私栏
    ui.setAuthUIPrivacy(uiconfig, builder);

    /// 切换方式控件
    ui.setAuthUISwitch(uiconfig, builder);

    /// 页面相关函数
    ui.setAuthUIPage(uiconfig, builder);

    // 创建AuthUI
    umVerifyHelper.setAuthUIConfig(builder.create());
  }
  public void setUIClickListener(@NonNull MethodCall call, @NonNull final Result result) {
    umVerifyHelper.setUIClickListener(new UMAuthUIControlClickListener() {
      public void onClick(String status, Context context, String res) {
        Log.d(TAG, "onUIClick:status=" + status + ";res=" + res);
        JSONObject data = JSONObject.parseObject(res);
        JSONObject jsonObject = util.retJSONObject(status,"onUIClickListener事件返回！", data);
        util.runMainThread(jsonObject, null, "sdkClickEventListener");
      }
    });
  }

  /**
   * @funtion addCustomTextWidget 添加自定义TextView
   * @param params
   * @param builder
   */
  @RequiresApi(api = Build.VERSION_CODES.P)
  private void _addCustomTextViewWidget(Map params, UMAuthUIConfig.Builder builder) {
    Log.d(TAG, "addCustomTextView:params=" + params);
    TextView customView = new TextView(context);
    _addAuthRegistViewConfig(customView, params, UMAuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY, "onClicked textView widget.");
  }

  /**
   * @function _addCustomButtonWidget 添加自定义添加ButtonWidget
   * @param params {Map}
   * @param builder {UMAuthUIConfig.Builder}
   */
  @RequiresApi(api = Build.VERSION_CODES.P)
  private void _addCustomButtonWidget(Map params, UMAuthUIConfig.Builder builder) {
    Log.d(TAG, "addCustomButtonWidgets:params=" + params);
    Button customWidget = new Button(context);
    // 设置背景图（只支持button设置）
    String btnNormalImageName = (String) params.get("btnNormalImageName");
    String btnPressedImageName = (String) params.get("btnPressedImageName");
    if (btnPressedImageName == null) {
      btnPressedImageName = btnNormalImageName;
    }
    if(btnNormalImageName != null) {
      ui.setButtonSelector(customWidget, btnNormalImageName, btnPressedImageName);
    }
    _addAuthRegistViewConfig(customWidget, params, UMAuthRegisterViewConfig.RootViewId.ROOT_VIEW_ID_BODY,"onClicked button widget.");
  }

  /**
   * @funtion _addAuthRegistViewConfig 设置公共自定义weiget
   * @param customWidget
   * @param params
   * @param rootViewId ROOT_VIEW_ID_TITLE_BAR, ROOT_VIEW_ID_BODY,ROOT_VIEW_ID_NUMBER
   * @param msg
   */
  @RequiresApi(api = Build.VERSION_CODES.P)
  private void _addAuthRegistViewConfig(TextView customWidget, Map params, int rootViewId, final String msg) {
    TextView widgetView = ui.setCommonCustomWidget(customWidget, params);
    // 点击事件 id
    Object widgetId = util.getValueByMapKey(params, "widgetId");
    String _widgetId;
    if(widgetId == null) {
      _widgetId = util.getUUID();
    } else {
      _widgetId = (String) widgetId;
    }
    final  JSONObject jsonObject = new JSONObject();
    jsonObject.put("widgetId", _widgetId);
    umVerifyHelper.addAuthRegistViewConfig(_widgetId, new UMAuthRegisterViewConfig.Builder()
      .setView(widgetView)
      .setRootViewId(rootViewId)
      .setCustomInterface(new UMCustomInterface() {
        @Override
        public void onClick(Context context) {
          Log.d(TAG, msg);
          util.runMainThread(jsonObject, null, "customClickEventListener");
        }
      }).build());
  }

  /**
   * @funtion checkVerifyEnable SDK环境检查函数，检查终端是否支持号码认证，通过UMTokenResultListener返回code
   * @param type 1:本机号码校验 2：一键登录
   *  600024 终端支持认证
   *  600013 系统维护，功能不可用
   */
  private boolean checkVerifyEnable(int type) {
    boolean checkEnvAvailable = false;
    if (umVerifyHelper != null) {
      checkEnvAvailable = umVerifyHelper.checkEnvAvailable() && checkCarrierName();
    }
    return checkEnvAvailable;
  }

  /**
   * @function checkCarrierName 检查运营商是否合规，不支持境外卡一键登录
   * @return boolean
   */
  public boolean checkCarrierName() {
    boolean isTrue = false;
    String currentCarrierName;
    if (umVerifyHelper != null) {
      currentCarrierName = umVerifyHelper.getCurrentCarrierName();
      Log.d("currentCarrierName", "" + currentCarrierName);
      isTrue = currentCarrierName.equals("CMCC") || currentCarrierName.equals("CUCC") || currentCarrierName.equals("CTCC");
    }
    return isTrue;
  }

  /// 以下为生命周期
  /**
   * This {@code FlutterPlugin} has been associated with a {@link FlutterEngine} instance.
   *
   * <p>Relevant resources that this {@code FlutterPlugin} may need are provided via the {@code
   * binding}. The {@code binding} may be cached and referenced until {@link
   * #onDetachedFromEngine(FlutterPluginBinding)} is invoked and returns.
   *
   * @param binding
   */
  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
    Log.d("TAG", "onAttachedToEngine");
    methodChannel = new MethodChannel(binding.getBinaryMessenger(), "uverify");
    methodChannel.setMethodCallHandler(this);
    context = binding.getApplicationContext();
    ui = new UverifyUI(context, methodChannel);
    util = new UverifyUtil(context, methodChannel);
  }

  /**
   * This {@code FlutterPlugin} has been removed from a {@link FlutterEngine} instance.
   *
   * <p>The {@code binding} passed to this method is the same instance that was passed in {@link
   * #onAttachedToEngine(FlutterPluginBinding)}. It is provided again in this method as a
   * convenience. The {@code binding} may be referenced during the execution of this method, but it
   * must not be cached or referenced after this method returns.
   *
   * <p>{@code FlutterPlugin}s should release all resources in this method.
   *
   * @param binding
   */
  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {}

  /**
   * This {@code ActivityAware} {@link FlutterPlugin} is now associated with an {@link Activity}.
   *
   * <p>This method can be invoked in 1 of 2 situations:
   *
   * <ul>
   *   <li>This {@code ActivityAware} {@link FlutterPlugin} was just added to a {@link
   *       FlutterEngine} that was already connected to a running {@link Activity}.
   *   <li>This {@code ActivityAware} {@link FlutterPlugin} was already added to a {@link
   *       FlutterEngine} and that {@link FlutterEngine} was just connected to an {@link Activity}.
   * </ul>
   * <p>
   * The given {@link ActivityPluginBinding} contains {@link Activity}-related references that an
   * {@code ActivityAware} {@link FlutterPlugin} may require, such as a reference to the actual
   * {@link Activity} in question. The {@link ActivityPluginBinding} may be referenced until either
   * {@link #onDetachedFromActivityForConfigChanges()} or {@link #onDetachedFromActivity()} is
   * invoked. At the conclusion of either of those methods, the binding is no longer valid. Clear
   * any references to the binding or its resources, and do not invoke any further methods on the
   * binding or its resources.
   *
   * @param binding
   */
  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    activity = binding.getActivity();
  }

  /**
   * The {@link Activity} that was attached and made available in {@link
   * #onAttachedToActivity(ActivityPluginBinding)} has been detached from this {@code
   * ActivityAware}'s {@link FlutterEngine} for the purpose of processing a configuration change.
   *
   * <p>By the end of this method, the {@link Activity} that was made available in {@link
   * #onAttachedToActivity(ActivityPluginBinding)} is no longer valid. Any references to the
   * associated {@link Activity} or {@link ActivityPluginBinding} should be cleared.
   *
   * <p>This method should be quickly followed by {@link
   * #onReattachedToActivityForConfigChanges(ActivityPluginBinding)}, which signifies that a new
   * {@link Activity} has been created with the new configuration options. That method provides a
   * new {@link ActivityPluginBinding}, which references the newly created and associated {@link
   * Activity}.
   *
   * <p>Any {@code Lifecycle} listeners that were registered in {@link
   * #onAttachedToActivity(ActivityPluginBinding)} should be deregistered here to avoid a possible
   * memory leak and other side effects.
   */
  @Override
  public void onDetachedFromActivityForConfigChanges() {}

  /**
   * This plugin and its {@link FlutterEngine} have been re-attached to an {@link Activity} after
   * the {@link Activity} was recreated to handle configuration changes.
   *
   * <p>{@code binding} includes a reference to the new instance of the {@link Activity}. {@code
   * binding} and its references may be cached and used from now until either {@link
   * #onDetachedFromActivityForConfigChanges()} or {@link #onDetachedFromActivity()} is invoked. At
   * the conclusion of either of those methods, the binding is no longer valid. Clear any references
   * to the binding or its resources, and do not invoke any further methods on the binding or its
   * resources.
   *
   * @param binding
   */
  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {}

  /**
   * This plugin has been detached from an {@link Activity}.
   *
   * <p>Detachment can occur for a number of reasons.
   *
   * <ul>
   *   <li>The app is no longer visible and the {@link Activity} instance has been destroyed.
   *   <li>The {@link FlutterEngine} that this plugin is connected to has been detached from its
   *       {@link FlutterView}.
   *   <li>This {@code ActivityAware} plugin has been removed from its {@link FlutterEngine}.
   * </ul>
   * <p>
   * By the end of this method, the {@link Activity} that was made available in {@link
   * #onAttachedToActivity(ActivityPluginBinding)} is no longer valid. Any references to the
   * associated {@link Activity} or {@link ActivityPluginBinding} should be cleared.
   *
   * <p>Any {@code Lifecycle} listeners that were registered in {@link
   * #onAttachedToActivity(ActivityPluginBinding)} or {@link
  * #onReattachedToActivityForConfigChanges(ActivityPluginBinding)} should be deregistered here to
   * avoid a possible memory leak and other side effects.
   */
  @Override
  public void onDetachedFromActivity() {}
}